home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Dr. Windows 3
/
dr win3.zip
/
dr win3
/
NEW_TECH
/
AWKSRC.ZIP
/
BUILTIN.C
< prev
next >
Wrap
C/C++ Source or Header
|
1993-09-27
|
24KB
|
1,129 lines
/*
* builtin.c - Builtin functions and various utility procedures
*/
/*
* Copyright (C) 1986, 1988, 1989, 1991, 1992 the Free Software Foundation, Inc.
*
* This file is part of GAWK, the GNU implementation of the
* AWK Progamming Language.
*
* GAWK is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* GAWK is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with GAWK; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "awk.h"
#ifndef SRANDOM_PROTO
extern void srandom P((int seed));
#endif
extern char *initstate P((unsigned seed, char *state, int n));
extern char *setstate P((char *state));
extern long random P((void));
extern NODE **fields_arr;
extern int output_is_tty;
static NODE *sub_common P((NODE *tree, int global));
#ifdef GFMT_WORKAROUND
char *gfmt P((double g, int prec, char *buf));
#endif
#ifdef _CRAY
/* Work around a problem in conversion of doubles to exact integers. */
#include <float.h>
#define Floor(n) floor((n) * (1.0 + DBL_EPSILON))
#define Ceil(n) ceil((n) * (1.0 + DBL_EPSILON))
/* Force the standard C compiler to use the library math functions. */
extern double exp(double);
double (*Exp)() = exp;
#define exp(x) (*Exp)(x)
extern double log(double);
double (*Log)() = log;
#define log(x) (*Log)(x)
#else
#define Floor(n) floor(n)
#define Ceil(n) ceil(n)
#endif
/* Builtin functions */
NODE *
do_exp(tree)
NODE *tree;
{
NODE *tmp;
double d, res;
#ifndef exp
double exp P((double));
#endif
tmp= tree_eval(tree->lnode);
d = force_number(tmp);
free_temp(tmp);
errno = 0;
res = exp(d);
if (errno == ERANGE)
warning("exp argument %g is out of range", d);
return tmp_number((AWKNUM) res);
}
NODE *
do_index(tree)
NODE *tree;
{
NODE *s1, *s2;
register char *p1, *p2;
register int l1, l2;
long ret;
s1 = tree_eval(tree->lnode);
s2 = tree_eval(tree->rnode->lnode);
force_string(s1);
force_string(s2);
p1 = s1->stptr;
p2 = s2->stptr;
l1 = s1->stlen;
l2 = s2->stlen;
ret = 0;
if (IGNORECASE) {
while (l1) {
if (l2 > l1)
break;
if (casetable[(int)*p1] == casetable[(int)*p2]
&& (l2 == 1 || strncasecmp(p1, p2, l2) == 0)) {
ret = 1 + s1->stlen - l1;
break;
}
l1--;
p1++;
}
} else {
while (l1) {
if (l2 > l1)
break;
if (*p1 == *p2
&& (l2 == 1 || STREQN(p1, p2, l2))) {
ret = 1 + s1->stlen - l1;
break;
}
l1--;
p1++;
}
}
free_temp(s1);
free_temp(s2);
return tmp_number((AWKNUM) ret);
}
NODE *
do_int(tree)
NODE *tree;
{
NODE *tmp;
double floor P((double));
double ceil P((double));
double d;
tmp = tree_eval(tree->lnode);
d = force_number(tmp);
if (d >= 0)
d = Floor(d);
else
d = Ceil(d);
free_temp(tmp);
return tmp_number((AWKNUM) d);
}
NODE *
do_length(tree)
NODE *tree;
{
NODE *tmp;
int len;
tmp = tree_eval(tree->lnode);
len = force_string(tmp)->stlen;
free_temp(tmp);
return tmp_number((AWKNUM) len);
}
NODE *
do_log(tree)
NODE *tree;
{
NODE *tmp;
#ifndef log
double log P((double));
#endif
double d, arg;
tmp = tree_eval(tree->lnode);
arg = (double) force_number(tmp);
if (arg < 0.0)
warning("log called with negative argument %g", arg);
d = log(arg);
free_temp(tmp);
return tmp_number((AWKNUM) d);
}
/* %e and %f formats are not properly implemented. Someone should fix them */
/* Actually, this whole thing should be reimplemented. */
NODE *
do_sprintf(tree)
NODE *tree;
{
#define bchunk(s,l) if(l) {\
while((l)>ofre) {\
erealloc(obuf, char *, osiz*2, "do_sprintf");\
ofre+=osiz;\
osiz*=2;\
}\
memcpy(obuf+olen,s,(l));\
olen+=(l);\
ofre-=(l);\
}
/* Is there space for something L big in the buffer? */
#define chksize(l) if((l)>ofre) {\
erealloc(obuf, char *, osiz*2, "do_sprintf");\
ofre+=osiz;\
osiz*=2;\
}
/*
* Get the next arg to be formatted. If we've run out of args,
* return "" (Null string)
*/
#define parse_next_arg() {\
if(!carg) { toofew = 1; break; }\
else {\
arg=tree_eval(carg->lnode);\
carg=carg->rnode;\
}\
}
NODE *r;
int toofew = 0;
char *obuf;
int osiz, ofre, olen;
static char chbuf[] = "0123456789abcdef";
static char sp[] = " ";
char *s0, *s1;
int n0;
NODE *sfmt, *arg;
register NODE *carg;
long fw, prec, lj, alt, big;
long *cur;
long val;
#ifdef sun386 /* Can't cast unsigned (int/long) from ptr->value */
long tmp_uval; /* on 386i 4.0.1 C compiler -- it just hangs */
#endif
unsigned long uval;
int sgn;
int base;
char cpbuf[30]; /* if we have numbers bigger than 30 */
char *cend = &cpbuf[30];/* chars, we lose, but seems unlikely */
char *cp;
char *fill;
double tmpval;
char *pr_str;
int ucasehex = 0;
char signchar = 0;
int len;
emalloc(obuf, char *, 120, "do_sprintf");
osiz = 120;
ofre = osiz - 1;
olen = 0;
sfmt = tree_eval(tree->lnode);
sfmt = force_string(sfmt);
carg = tree->rnode;
for (s0 = s1 = sfmt->stptr, n0 = sfmt->stlen; n0-- > 0;) {
if (*s1 != '%') {
s1++;
continue;
}
bchunk(s0, s1 - s0);
s0 = s1;
cur = &fw;
fw = 0;
prec = 0;
lj = alt = big = 0;
fill = sp;
cp = cend;
s1++;
retry:
--n0;
switch (*s1++) {
case '%':
bchunk("%", 1);
s0 = s1;
break;
case '0':
if (fill != sp || lj)
goto lose;
if (cur == &fw)
fill = "0"; /* FALL through */
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
if (cur == 0)
goto lose;
*cur = s1[-1] - '0';
while (n0 > 0 && *s1 >= '0' && *s1 <= '9') {
--n0;
*cur = *cur * 10 + *s1++ - '0';
}
goto retry;
case '*':
if (cur == 0)
goto lose;
parse_next_arg();
*cur = (long) force_number(arg);
free_temp(arg);
goto retry;
case ' ': /* print ' ' or '-' */
case '+': /* print '+' or '-' */
signchar = *(s1-1);
goto retry;
case '-':
if (lj || fill != sp)
goto lose;
lj++;
goto retry;
case '.':
if (cur != &fw)
goto lose;
cur = ≺
goto retry;
case '#':
if (alt)
goto lose;
alt++;
goto retry;
case 'l':
if (big)
goto lose;
big++;
goto retry;
case 'c':
parse_next_arg();
if (arg->flags & NUMBER) {
#ifdef sun386
tmp_uval = arg->numbr;
uval= (unsigned long) tmp_uval;
#else
uval = (unsigned long) arg->numbr;
#endif
cpbuf[0] = (char) uval;
prec = 1;
pr_str = cpbuf;
goto dopr_string;
}
if (! prec)
prec = 1;
else if (prec > (signed) arg->stlen)
prec = arg->stlen;
pr_str = arg->stptr;
goto dopr_string;
case 's':
parse_next_arg();
arg = force_string(arg);
if (!prec || prec > (signed) arg->stlen)
prec = arg->stlen;
pr_str = arg->stptr;
dopr_string:
if (fw > prec && !lj) {
while (fw > prec) {
bchunk(sp, 1);
fw--;
}
}
bchunk(pr_str, (int) prec);
if (fw > prec) {
while (fw > prec) {
bchunk(sp, 1);
fw--;
}
}
s0 = s1;
free_temp(arg);
break;
case 'd':
case 'i':
parse_next_arg();
val = (long) force_number(arg);
free_temp(arg);
if (val < 0) {
sgn = 1;
val = -val;
} else
sgn = 0;
do {
*--cp = '0' + val % 10;
val /= 10;
} while (val);
if (sgn)
*--cp = '-';
else if (signchar)
*--cp = signchar;
if (prec > fw)
fw = prec;
prec = cend - cp;